﻿namespace PrismEx.Fixtures.Steps
{
    using System;

    using FluentAssertions;

    using Microsoft.Practices.Prism.Events;

    using Moq;

    using NUnit.Framework;

    using TechTalk.SpecFlow;

    [Binding]
    public class EventAggregatorExtensionsSteps
    {
        [SetUp]
        public void Setup()
        {
            ScenarioContext.Current["TestDomain"] = new TestDomain<FakeEvent>();
        }

        [Given(@"An event aggregator has been created")]
        public void GivenAnEventAggregatorHasBeenCreated()
        {
            var testDomain = new TestDomain<FakeEvent>();
            ScenarioContext.Current["TestDomain"] = testDomain;

            var eventMock = new Mock<FakeEvent>();
            ScenarioContext.Current["Event"] = eventMock.Object;

            var eventAggregatorMock = new Mock<IEventAggregator>();
            eventAggregatorMock.Setup(e => e.GetEvent<FakeEvent>()).Returns(eventMock.Object);

            testDomain.WithEventAggregator(eventAggregatorMock.Object);
        }

        [Given(@"An event aggregator has been created with a real event")]
        public void GivenAnEventAggregatorHasBeenCreatedWithalEventARe()
        {
            var testDomain = new TestDomain<FakeEvent>();
            ScenarioContext.Current["TestDomain"] = testDomain;

            var @event = new FakeEvent();
            ScenarioContext.Current["Event"] = @event;

            var eventAggregatorMock = new Mock<IEventAggregator>();
            eventAggregatorMock.Setup(e => e.GetEvent<FakeEvent>()).Returns(@event);

            testDomain.WithEventAggregator(eventAggregatorMock.Object);
        }

        [When(@"an event is published by type only")]
        public void WhenAnEventIsPublishedByTypeOnly()
        {
            var testDomain = ScenarioContext.Current["TestDomain"] as TestDomain<FakeEvent>;
            testDomain.Publish();
        }

        [When(@"an event is published with an instance")]
        public void WhenAnEventIsPublishedWithAnInstance()
        {
            var testDomain = ScenarioContext.Current["TestDomain"] as TestDomain<FakeEvent>;
            var eventMock = ScenarioContext.Current["Event"] as FakeEvent;

            testDomain.Publish(eventMock);
        }


        [Then(@"the publish method have been called")]
        public void ThenThePublishMethodHaveBeenCalled()
        {
            var @event = ScenarioContext.Current["Event"] as FakeEvent;

            Mock.Get(@event).Verify(e => e.Publish(null));
        }

        [Then(@"the publish method should have been called with no payload")]
        public void ThenThePublishMethodShouldHaveBeenCalledWithNoPayload()
        {
            var @event = ScenarioContext.Current["Event"] as FakeEvent;

            Mock.Get(@event).Verify(e => e.Publish(null));
        }

        [Then(@"the publish method should have been called with an event payload")]
        public void ThenThePublishMethodShouldHaveBeenCalledWithAnEventPayload()
        {
            var @event = ScenarioContext.Current["Event"] as FakeEvent;
            var eventMock = Mock.Get(@event) as Mock<FakeEvent>;
            
            Mock.Get(@event).Verify(e => e.Publish(@event));
        }

        [Then(@"the subscription method should have been called")]
        public void ThenTheSubscriptionMethodShouldHaveBeenCalled()
        {
            var testDomain = ScenarioContext.Current["TestDomain"] as TestDomain<FakeEvent>;
            var @event = ScenarioContext.Current["Event"] as FakeEvent;

            Mock.Get(@event).Verify(e => e.Subscribe(It.IsAny<Action<FakeEvent>>()));
        }

        [Then(@"the payload should be the expected value")]
        public void ThenThePayloadShouldBeTheExpectedValue()
        {
            ScenarioContext.Current.Pending();
        }

        [When(@"an event is subscribed to")]
        public void WhenAnEventIsSubscribedTo()
        {
            var testDomain = ScenarioContext.Current["TestDomain"] as TestDomain<FakeEvent>;

            testDomain.WithSubscription(a => { });
        }

        [When(@"an event is publishedby type only")]
        public void WhenAnEventIsPublishedbyTypeOnly()
        {
            var testDomain = ScenarioContext.Current["TestDomain"] as TestDomain<FakeEvent>;

            testDomain.Publish();
        }


        [Then(@"the subscription delegate should be called")]
        public void ThenTheSubscriptionDelegateShouldBeCalled()
        {
            var testDomain = ScenarioContext.Current["TestDomain"] as TestDomain<FakeEvent>;

            testDomain.SubscriptionDelegateCallCount.Should().Be(1);
        }
    }
}